#ifndef TICKETINTERFACE_H
#define TICKETINTERFACE_H

#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QWeakPointer>

class Ticket;
struct TicketField;
class TicketQuery;
class BaseTicketItemModel;
class QAbstractItemDelegate;
class QUrl;

class TicketErrorPrivate;
class TicketError {
public:
    // TODO: rename some of these so they are a little bit more consistent
    enum ErrorType {
        ErrorUndefined,
        ErrorTicketNotFound, // No such ticket
        ErrorBackendFailure, // Network etc errors from backend
        ErrorBackendBadData, // Malformed data from backend
        ErrorCouldNotLoadTicket, // Ticket could not be loaded
        ErrorFailedToLoadHistory,
        ErrorFailedToLoadActions,
        ErrorFailedToLoadFields,
        ErrorTicketCreateFailed,
        ErrorUnableToListTickets,
        ErrorFailedToUpdateTicket,
        ErrorFailedToRetrieveRecentChanges
    };
    TicketError(ErrorType type, QString error, int originalCode = -1, const Ticket *ticket = 0);
    TicketError(const TicketError &other);
    ~TicketError();

    ErrorType type() const;
    QString error() const;
    int originalCode() const;
    const Ticket *ticket() const;
private:
    friend class TicketErrorPrivate;
    QSharedDataPointer<TicketErrorPrivate> d;
};

QDebug operator<<(QDebug d, const TicketError &p);

class QSettings;

class ITicketBackendConfiguration : public QObject
{
    Q_OBJECT
public:
    virtual QString id() const = 0;

    virtual void readSettings(const QSettings &settings) = 0;
    virtual void writeSettings(QSettings &settings) = 0;
};

class ITicketExplorerBackend : public QObject
{
    Q_OBJECT
public:
    ITicketExplorerBackend(ITicketBackendConfiguration *config, QObject *parent = 0);
    virtual ~ITicketExplorerBackend();

    virtual QString id() const = 0;
    virtual BaseTicketItemModel *queryModel(TicketQuery query) = 0;
    virtual QAbstractItemDelegate *listDelegate() const = 0;

    // Create an entirely new ticket
    virtual Ticket *createTicket() = 0;

    // TODO: rename
    virtual void storeTicket(Ticket *ticket, const QString &comment = "") = 0;
    virtual void refreshTicket(Ticket *ticket) = 0;

    // Fetch ticket changelog
    virtual void loadHistory(Ticket *ticket) = 0;
    virtual void loadAvailableActions(Ticket *ticket) = 0;
    virtual QList<TicketField> getAvailableFields() = 0;
    virtual void updateFields() = 0;
    virtual void loadChangedTickets(const QDateTime &since) = 0;

    // Return the configured remote URL and username for this session. The default
    // implementation returns "" for both. Some backends may not have any knowledge
    // about the concept of URLs or usernames.
    virtual QUrl url() const;
    virtual QString username() const;

signals:
    void fieldsUpdated();
    void actionsUpdated();
    void changedTickets(const QList<int> &tickets);
    void error(const TicketError &error);
protected:
    ITicketBackendConfiguration *m_config;
};


class TicketBackendConfigPanel
{

};

// Perhaps give this a less monstrous name
class ITicketBackendConfigurationWidgetFactory: public QObject
{
    Q_OBJECT
public:
    ITicketBackendConfigurationWidgetFactory();
    virtual ~ITicketBackendConfigurationWidgetFactory() {}

    virtual QString displayName() const = 0;
    virtual QString id() const = 0;

    virtual TicketBackendConfigPanel *configurationWidget() = 0;
};

class TicketExplorerBackendContext : public QObject
{
    Q_OBJECT

public:
    TicketExplorerBackendContext(ITicketExplorerBackend *backend, QObject *parent = 0);
    virtual ~TicketExplorerBackendContext() {}

    void updateHistory(Ticket *ticket) const;
    void updateActions(Ticket *ticket) const;
    void storeTicket(Ticket *ticket, const QString &comment = "") const;
    void refreshTicket(Ticket *ticket) const;

private:
    QWeakPointer<ITicketExplorerBackend> m_backend;
};

#endif // TICKETINTERFACE_H
